﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OVS_FormsRecognition.Manager;
using System.Diagnostics;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;
using Emgu.CV.GPU;
using OVS.BLL;
using OVS.BusinessObjects;
using System.Drawing.Imaging;

namespace OVS_TrajectoryCalculation.Manager
{
    public class TrajectoryCalculationManager
    {
        #region attributs
        //Label _LabelLastAlertInfo;


        public Capture _capture;
        public bool _captureInProgress;
        public Image<Bgr, Byte> frame { get; set; }
        public Image<Bgr, Byte> opticalFlowFrame2 { get; set; }
        PointF Frame_Precedent;
        Timer timer = new Timer();
        string dateN;
        public int compteur = 0;
        public int first_passsage = 0;
        //tableau contenan les id associer à son image des alerts.
        private static Dictionary<int, Image<Bgr, Byte>> dictionary = new Dictionary<int, Image<Bgr, Byte>>();



        #endregion

        /// <summary>
        /// Logger par défaut du ManagerUtilisateurs
        /// </summary>
        private static readonly log4net.ILog _Log = log4net.LogManager.GetLogger(typeof(TrajectoryCalculationManager));

        #region Gestion du singleton

        /// <summary>
        /// Instance locale pour héberger le singleton
        /// </summary>
        static TrajectoryCalculationManager instance = null;

        /// <summary>
        /// Objet permettant la gestion des LOCK lors de l'instanciation
        /// </summary>
        static readonly object padlock = new object();

        /// <summary>
        /// Constructeur par défaut
        /// </summary>
        TrajectoryCalculationManager()
        {
            if (_Log.IsDebugEnabled)
                _Log.DebugFormat("Nouvelle instance de '{0}'", this.GetType().ToString());

        }

        /// <summary>
        /// Déclaration unique par gestion du singleton
        /// </summary>
        public static TrajectoryCalculationManager Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new TrajectoryCalculationManager();
                    }
                    return instance;
                }
            }
        }

        #endregion Gestion du singleton

        /// <summary>
        /// Sets the window for debug.
        /// </summary>
        /// <param name="pLabelLastAlertInfo">The p label last alert info.</param>
        /* public void setWindowForDebug(Label pLabelLastAlertInfo)
          {
              _LabelLastAlertInfo = pLabelLastAlertInfo;
          }*/

        /// <summary>
        /// Registers the event handler.
        /// </summary>
        /// <param name="pSizeCalculationStartEvent">The p size calculation start event.</param>
        public void registerEventHandler()
        {
            FormsRecognitionManager.Instance.TrajectoryCalculationEventNewCapture += new FormsRecognitionManager.TrajectoryCalculationEventHandler(CallBackTrajectoryCalculationEventNewCapture);
            FormsRecognitionManager.Instance.TrajectoryCalculationEventStopCapture += new FormsRecognitionManager.TrajectoryCalculationEventHandler(CallBackTrajectoryCalculationEventStopCapture);
        }

        /// <summary>
        /// Calls the back size calculation start event.
        /// </summary>
        /// <param name="nullObject">The null object.</param>
        /// <param name="pSizeCalculationEventArgs">The <see cref="SizeCalculationEventArgs" /> instance containing the event data.</param>
        private void CallBackTrajectoryCalculationEventNewCapture(object nullObject, TrajectoryCalculationEventArgs pSizeCalculationEventArgs)
        {
            _Log.Debug("new event ListenerTrajCalculationStartEvent !!!");

            /*if (_LabelLastAlertInfo != null)
             {
                 _LabelLastAlertInfo.Content = DateTime.Now.ToString();
             }*/
            //new picture for drawing point
            // draw the first point in red.

            //verifie si une image existe deja pour cette événement dans la biblioteque.
            if (dictionary.ContainsKey(pSizeCalculationEventArgs.Id_Alert))
            {
                // MessageBox.Show("il y a une image en cour");
                ProcessFrame(pSizeCalculationEventArgs.Rect, pSizeCalculationEventArgs.Image_Detecte, pSizeCalculationEventArgs.Id_Alert);
            }
            else
            {
                // MessageBox.Show("il y a pas d'image en cour, on ajoute un enregistrement dans la bibliotheque");
                Image<Bgr, Byte> FlowFrame = pSizeCalculationEventArgs.Image_Detecte;
                //FlowFrame = pSizeCalculationEventArgs.Image_Detecte;
                dictionary.Add(pSizeCalculationEventArgs.Id_Alert, FlowFrame);
                // MessageBox.Show("Fin du nouvelle ajout dans la bibliotheque");
                ProcessFrame(pSizeCalculationEventArgs.Rect, pSizeCalculationEventArgs.Image_Detecte, pSizeCalculationEventArgs.Id_Alert);

                first_passsage = first_passsage + 1;
            }

            // init();


            //start the capture
            ////////////////////////////////////////////////////////////////////////
            //label_Marche_Arret.Text = "Marche";
            /////////////////////////////////////////////////////////////////////////
            //en parametre il le faut l'objet.


        }
        /// <summary>
        /// Calls the back size calculation start event.
        /// </summary>
        /// <param name="nullObject">The null object.</param>
        /// <param name="pSizeCalculationEventArgs">The <see cref="SizeCalculationEventArgs" /> instance containing the event data.</param>
        private void CallBackTrajectoryCalculationEventStopCapture(object nullObject, TrajectoryCalculationEventArgs pSizeCalculationEventArgs)
        {
            string dateN;

            _Log.Debug("new event ListenerTrajCalculationStartEvent !!!");
            //MessageBox.Show("Dans L'evenement stop traj");
            /* if (_LabelLastAlertInfo != null)
              {
                  _LabelLastAlertInfo.Content = "STOP";
              }*/
            //Stop the draw on the picture and save this picture (à la racine du projet pour le moment)
            //enregistrement de l'image avec les points de la trajectoire.

            dateN = DateTime.Now.ToShortDateString();
            dateN = dateN.Replace("/", "_");
            //on recupere l'élément opticalFlowFrame2(la ou est tracer l'image) sur Trajectory et on l'enregistre.
            String Chemin_Image = @"C:\OVS\Images_Traj\Traj_" + dateN + "_" + pSizeCalculationEventArgs.Id_Alert + ".jpg";

            try
            {
                //MessageBox.Show("Dans le try");
                //opticalFlowFrame2.ToBitmap().Save(Chemin_Image);
                if (dictionary.ContainsKey(pSizeCalculationEventArgs.Id_Alert))
                {
                    //MessageBox.Show("On enregistre l'image de trajectoire");
                    Image<Bgr, Byte> opticalFlowFrame4 = dictionary[pSizeCalculationEventArgs.Id_Alert];

                    // Tu sauvegrdes sous une autre extension
                    opticalFlowFrame4.ToBitmap().Save(Chemin_Image, ImageFormat.Jpeg);

                    opticalFlowFrame4.Dispose();

                    dictionary.Remove(pSizeCalculationEventArgs.Id_Alert);
                }
                else
                {
                    MessageBox.Show("Erreur pendant l'enregistrement de l'image trajectoire: Id 'alert n'existe pas dans le dictionary ");
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show("Erreur pendant l'enregistrement de l'image trajectoire: " + ex.Message);
            }

            try
            {   

                //MessageBox.Show("On met à jour le chemin de l'image traj de l'alert");
                Alert currentAlert = AlertBLL.Instance.GetAlert(pSizeCalculationEventArgs.Id_Alert);
                currentAlert.aler_image_traj = Chemin_Image;

                // currentAlert.aler_image_traj=Chemin_Image;
                //Update de l'alerte !
                AlertBLL.Instance.UpdateAlert(currentAlert);
                //MessageBox.Show(currentAlert.aler_image_traj);
            }
            catch (Exception ex)
            {

                MessageBox.Show("Mise à jour du chemin de l'image trajectoire de l'alert en cour: " + ex.Message);
            }


            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // TrajectoryCalculationMain.label_Marche_Arret.Text = "Arrêt";
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        }


        private void init()
        {
            opticalFlowFrame2 = new Image<Bgr, Byte>(640, 360);
        }



        private void ProcessFrame(Rectangle RectDetec, Image<Bgr, Byte> Image_Detecte, int Id_Alert)
        {
            // MessageBox.Show("Dans processFrame");
            //frame = _capture.QueryFrame();
            frame = Image_Detecte;

            Rectangle rec = new Rectangle(RectDetec.X, RectDetec.Y, 10, 10);

         
            //MessageBox.Show("Avancement 1");
            PointF Point_haut_gauche = new PointF(RectDetec.X, RectDetec.Y);

            //ce point est basé sur le coté bas gauche du rectangle, il est placé de sorte que ce soit le centre
            //MessageBox.Show("Avancement 2");
            PointF Point_central = new PointF(RectDetec.X + (RectDetec.Height / 2), RectDetec.Y + (RectDetec.Width / 2));


            //MessageBox.Show("Avancement 3");
            PointF Point_haut_droit = new PointF(RectDetec.X + RectDetec.Height, RectDetec.Y);
            PointF Point_bas_droit = new PointF(RectDetec.X + RectDetec.Height, RectDetec.Y + RectDetec.Width);

            //MessageBox.Show("Avancement 4");
            CircleF a = new CircleF(Point_haut_gauche, 2.0f);
            CircleF b = new CircleF(Point_haut_droit, 2.0f);
            CircleF c = new CircleF(Point_bas_droit, 2.0f);
            CircleF d = new CircleF(Point_central, 2.0f);


            //Je trace le point sur l'image de gauche
            if (first_passsage > 1)
            {
                // opticalFlowFrame2.Draw(d, new Bgr(Color.Goldenrod), 2);

                if (dictionary.ContainsKey(Id_Alert))
                {
                    Image<Bgr, Byte> opticalFlowFrame4 = Image_Detecte;
                    opticalFlowFrame4 = dictionary[Id_Alert];
                    opticalFlowFrame4.Draw(d, new Bgr(Color.Goldenrod), 2);
                    dictionary[Id_Alert] = opticalFlowFrame4;
                }

            }
            else
            {
                //MessageBox.Show("Preiere image, on trace le point en rouge");
                // opticalFlowFrame2.Draw(d, new Bgr(Color.Red), 2);
                if (dictionary.ContainsKey(Id_Alert))
                {
                    // MessageBox.Show("Ajout de limage avec le point dans la bibliotheque");
                    Image<Bgr, Byte> opticalFlowFrame4 =Image_Detecte;
                    opticalFlowFrame4 = dictionary[Id_Alert];
                    opticalFlowFrame4.Draw(d, new Bgr(Color.Red), 2);
                    dictionary[Id_Alert] = opticalFlowFrame4;
                    // MessageBox.Show("Fin de l'ajout de l'image avec le point dans la biblioteque");
                }

            }
           
            //on regarde le point de la frame avant pour le comparer au coordonnées de la frame en cour. 
            //On peut comme ça determiner si le mouvement suivant est en haut en bas a gauche ou a droite.
            if (Point_central.X > Frame_Precedent.X)
            {
                //label2.Text = "GAUCHE";
            }
            if (Point_central.X < Frame_Precedent.X)
            {
                //label2.Text = "DROITE";
            }
            if (Point_central.Y > Frame_Precedent.Y)
            {
                //label3.Text = "BAS";
            }
            if (Point_central.Y < Frame_Precedent.Y)
            {
                //label3.Text = "HAUT";
            }
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


            //on enregistre le point de la frame en cour pour le comparer avec la frame suivante.
            Frame_Precedent = Point_central;           

        }



    }
}
